#include "SkyNet.h"

void ACTIVATION(hls::stream<BDT> IFM_stream[32], hls::stream<ADT> OFM_stream[32], BDT BBUF[32], MDT MBUF[32])
{
	for (int w = 0; w < 83; w++)
	{
		for (int h = 0; h < 43; h++)
		{
#pragma HLS LOOP_FLATTEN
#pragma HLS PIPELINE II=1
			for (int c = 0; c < 32; c++)
			{
				BDT read_in = IFM_stream[c].read();
				int tmp_0 = read_in + BBUF[c];
				int tmp_1 = tmp_0 < 0 ? 0 : tmp_0;
				int tmp_2 = ((tmp_1 * MBUF[c]) >> nm) - 128;
				ADT y = tmp_2 < amin ? ADT(amin) : tmp_2 > amax ? ADT(amax) : ADT(tmp_2);
				if (h == 0 || h == 42 || w == 0 || w == 82)
				{
					OFM_stream[c].write(-128);
				}
				else
				{
					OFM_stream[c].write(y);
				}
			}
		}
	}
}

ADT MAX(ADT a, ADT b, ADT c, ADT d)
{
#pragma HLS INLINE
	ADT t1 = a > b ? a : b;
	ADT t2 = c > d ? c : d;
	return t1 > t2 ? t1 : t2;
}

void POOL(hls::stream<ADT> IFM_stream[32], hls::stream<BDT> OFM_stream[32])
{
	ADT line_buffer[32][2][40];
#pragma HLS ARRAY_PARTITION variable=line_buffer complete dim=1
#pragma HLS ARRAY_PARTITION variable=line_buffer complete dim=2
#pragma HLS ARRAY_PARTITION variable=line_buffer cyclic factor=2 dim=3

    for (ap_uint<8> w = 0; w < 83; w++)
	{
		for (ap_uint<8> h = 0; h < 43; h++)
		{
#pragma HLS LOOP_FLATTEN
#pragma HLS PIPELINE II=1
			for (ap_uint<8> c = 0; c < 32; c++)
			{
				ADT read_in = IFM_stream[c].read();
				if (w >= 1 && w <= 81 && h >= 1 && h <= 41)
				{
					line_buffer[c][w[0]][h - 1] = read_in;

					if (!w[0] && !h[0])
					{
						BDT write_out = (BDT) MAX(
							line_buffer[c][1][h - 2], line_buffer[c][0][h - 2],
							line_buffer[c][1][h - 1], line_buffer[c][0][h - 1]);
						OFM_stream[c].write(write_out);
					}
				}
			}
		}
	}
}
